﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Data;
using System.Collections;

namespace XQ.Extension
{
    /// <summary>
    /// Object对象
    /// </summary>
    public static class ObjectExtensions
    {
        /// <summary>
        /// 对方赋值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="this"></param>
        /// <param name="_new"></param>
        /// <returns></returns>
        public static T Copy<T>(this T @this, T _new) where T : class
        {
            if (@this == null)
                return _new;

            var p1 = @this.GetType().GetProperties();
            var p2 = _new.GetType().GetProperties();

            foreach (var item in p1)
            {
                foreach (var itme2 in p2)
                {
                    if (item.Name == itme2.Name && item.PropertyType == itme2.PropertyType)
                    {
                        try
                        {
                            Object obj = item.GetValue(@this, null);
                            itme2.SetValue(_new, obj, null);
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine(ex.Message);
                        }
                    }
                }
            }
            return @this;
        }


        /// <summary>
        /// 对方赋值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <permission cref="T1"></permission> 
        /// <param name="this"></param>
        /// <returns></returns>
        public static T1 To2<T, T1>(this T @this) where T : class
                                                  where T1 : new()

        {
            T1 _new = new T1();
            if (@this == null)
                return _new;

            var p1 = @this.GetType().GetProperties();
            var p2 = typeof(T1).GetProperties();

            foreach (var item in p1)
            {
                foreach (var itme2 in p2)
                {
                    if (item.Name == itme2.Name && item.PropertyType == itme2.PropertyType)
                    {
                        try
                        {
                            Object obj = item.GetValue(@this, null);
                            itme2.SetValue(_new, obj, null);
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine(ex.Message);
                        }
                    }
                }
            }
            return _new;
        }

        /// <summary>
        ///     A System.Object extension method that toes the given this.
        /// </summary>
        /// <typeparam name="T">Generic type parameter.</typeparam>
        /// <param name="this">this.</param>
        /// <returns>A T.</returns>
        /// <example>
        ///     <code>
        ///       using System;
        ///       using Microsoft.VisualStudio.TestTools.UnitTesting;
        /// 
        /// 
        ///       namespace ExtensionMethods.Examples
        ///       {
        ///           [TestClass]
        ///           public class System_Object_To
        ///           {
        ///               [TestMethod]
        ///               public void To()
        ///               {
        ///                   string nullValue = null;
        ///                   string value = &quot;1&quot;;
        ///                   object dbNullValue = DBNull.Value;
        /// 
        ///                   // Exemples
        ///                   var result1 = value.To&lt;int&gt;(); // return 1;
        ///                   var result2 = value.To&lt;int?&gt;(); // return 1;
        ///                   var result3 = nullValue.To&lt;int?&gt;(); // return null;
        ///                   var result4 = dbNullValue.To&lt;int?&gt;(); // return null;
        /// 
        ///                   // Unit Test
        ///                   Assert.AreEqual(1, result1);
        ///                   Assert.AreEqual(1, result2.Value);
        ///                   Assert.IsFalse(result3.HasValue);
        ///                   Assert.IsFalse(result4.HasValue);
        ///               }
        ///           }
        ///       }
        /// </code>
        /// </example>
        /// <example>
        ///     <code>
        ///       using System;
        ///       using Microsoft.VisualStudio.TestTools.UnitTesting;
        ///       using Z.ExtensionMethods.Object;
        /// 
        ///       namespace ExtensionMethods.Examples
        ///       {
        ///           [TestClass]
        ///           public class System_Object_To
        ///           {
        ///               [TestMethod]
        ///               public void To()
        ///               {
        ///                   string nullValue = null;
        ///                   string value = &quot;1&quot;;
        ///                   object dbNullValue = DBNull.Value;
        /// 
        ///                   // Exemples
        ///                   var result1 = value.To&lt;int&gt;(); // return 1;
        ///                   var result2 = value.To&lt;int?&gt;(); // return 1;
        ///                   var result3 = nullValue.To&lt;int?&gt;(); // return null;
        ///                   var result4 = dbNullValue.To&lt;int?&gt;(); // return null;
        /// 
        ///                   // Unit Test
        ///                   Assert.AreEqual(1, result1);
        ///                   Assert.AreEqual(1, result2.Value);
        ///                   Assert.IsFalse(result3.HasValue);
        ///                   Assert.IsFalse(result4.HasValue);
        ///               }
        ///           }
        ///       }
        /// </code>
        /// </example>
        public static T To<T>(this Object @this)
        {
            if (@this != null)
            {
                Type targetType = typeof(T);

                if (@this.GetType() == targetType)
                {
                    return (T)@this;
                }

                TypeConverter converter = TypeDescriptor.GetConverter(@this);
                if (converter != null)
                {
                    if (converter.CanConvertTo(targetType))
                    {
                        return (T)converter.ConvertTo(@this, targetType);
                    }
                }

                converter = TypeDescriptor.GetConverter(targetType);
                if (converter != null)
                {
                    if (converter.CanConvertFrom(@this.GetType()))
                    {
                        return (T)converter.ConvertFrom(@this);
                    }
                }

                if (@this == DBNull.Value)
                {
                    return (T)(object)null;
                }
            }

            return (T)@this;
        }
        /// <summary>
        ///     A System.Object extension method that toes the given this.
        /// </summary>
        /// <param name="this">this.</param>
        /// <param name="type">The type.</param>
        /// <returns>An object.</returns>
        /// <example>
        ///     <code>
        ///       using System;
        ///       using Microsoft.VisualStudio.TestTools.UnitTesting;
        /// 
        /// 
        ///       namespace ExtensionMethods.Examples
        ///       {
        ///           [TestClass]
        ///           public class System_Object_To
        ///           {
        ///               [TestMethod]
        ///               public void To()
        ///               {
        ///                   string nullValue = null;
        ///                   string value = &quot;1&quot;;
        ///                   object dbNullValue = DBNull.Value;
        /// 
        ///                   // Exemples
        ///                   var result1 = value.To&lt;int&gt;(); // return 1;
        ///                   var result2 = value.To&lt;int?&gt;(); // return 1;
        ///                   var result3 = nullValue.To&lt;int?&gt;(); // return null;
        ///                   var result4 = dbNullValue.To&lt;int?&gt;(); // return null;
        /// 
        ///                   // Unit Test
        ///                   Assert.AreEqual(1, result1);
        ///                   Assert.AreEqual(1, result2.Value);
        ///                   Assert.IsFalse(result3.HasValue);
        ///                   Assert.IsFalse(result4.HasValue);
        ///               }
        ///           }
        ///       }
        /// </code>
        /// </example>
        /// <example>
        ///     <code>
        ///       using System;
        ///       using Microsoft.VisualStudio.TestTools.UnitTesting;
        ///       using Z.ExtensionMethods.Object;
        /// 
        ///       namespace ExtensionMethods.Examples
        ///       {
        ///           [TestClass]
        ///           public class System_Object_To
        ///           {
        ///               [TestMethod]
        ///               public void To()
        ///               {
        ///                   string nullValue = null;
        ///                   string value = &quot;1&quot;;
        ///                   object dbNullValue = DBNull.Value;
        /// 
        ///                   // Exemples
        ///                   var result1 = value.To&lt;int&gt;(); // return 1;
        ///                   var result2 = value.To&lt;int?&gt;(); // return 1;
        ///                   var result3 = nullValue.To&lt;int?&gt;(); // return null;
        ///                   var result4 = dbNullValue.To&lt;int?&gt;(); // return null;
        /// 
        ///                   // Unit Test
        ///                   Assert.AreEqual(1, result1);
        ///                   Assert.AreEqual(1, result2.Value);
        ///                   Assert.IsFalse(result3.HasValue);
        ///                   Assert.IsFalse(result4.HasValue);
        ///               }
        ///           }
        ///       }
        /// </code>
        /// </example>
        /// ###
        /// <typeparam name="T">Generic type parameter.</typeparam>
        public static object To(this Object @this, Type type)
        {
            if (@this != null)
            {
                Type targetType = type;

                if (@this.GetType() == targetType)
                {
                    return @this;
                }

                TypeConverter converter = TypeDescriptor.GetConverter(@this);
                if (converter != null)
                {
                    if (converter.CanConvertTo(targetType))
                    {
                        return converter.ConvertTo(@this, targetType);
                    }
                }

                converter = TypeDescriptor.GetConverter(targetType);
                if (converter != null)
                {
                    if (converter.CanConvertFrom(@this.GetType()))
                    {
                        return converter.ConvertFrom(@this);
                    }
                }

                if (@this == DBNull.Value)
                {
                    return null;
                }
            }

            return @this;
        }

        /// <summary>
        /// Obj转换String 如果Null转换string.Empty
        /// </summary>
        /// <param name="this"></param>
        /// <returns></returns>
        public static string ToStr(this object @this)
        {
            if (@this == null)
                return string.Empty;
            return @this.ToString();
        }

        /// <summary>
        /// Obj转换String并去除空格
        /// </summary>
        /// <param name="this"></param>
        /// <returns></returns>
        public static string ToStrTrim(this object @this)
        {
            return @this.ToStr().Trim();
        }

        /// <summary>
        /// Obj转换String并大小
        /// </summary>
        /// <param name="this"></param>
        /// <returns></returns>
        public static string ToStrUpper(this object @this)
        {
            return @this.ToStr().ToUpper();
        }

        /// <summary>
        /// Obj转换String并大小
        /// </summary>
        /// <param name="this"></param>
        /// <returns></returns>
        public static string ToStrLower(this object @this)
        {
            return @this.ToStr().ToLower();
        }


        /// <summary>
        /// 打印对象数据
        /// </summary>
        /// <param name="this"></param>
        /// <param name="nulStr"></param>
        public static void ConsolePrintProperty(this object @this, string nulStr = "")
        {
            Type type = null;
            if (@this == null)
            {
                return;
            }
            else
            {
                type = @this.GetType();
            }

            var prop = type.GetProperties();
            if (prop.Any())
            {
                Console.WriteLine();
                for (int i = 0; i < prop.Length; i++)
                {
                    var po = prop[i];
                    Console.Write(nulStr + po.Name);
                    Console.Write(":");
                    if (@this != null)
                    {
                        var val = po.GetValue(@this, null);
                        if (val == null)
                        {
                            Console.WriteLine();
                            continue;
                        }
                        var valTp = val.GetType();
                        if (valTp.IsGenericType && (valTp.GetGenericTypeDefinition() == typeof(List<>)))
                        {
                            //  创建List的实例
                            var listTypeInstance = val as IEnumerable;
                            foreach (var item in listTypeInstance)
                            {
                                ConsolePrint(item.GetType(), item, nulStr);
                            }
                        }
                        else
                        {
                            ConsolePrint(valTp, val, nulStr);
                        }
                    }
                    Console.WriteLine();
                }
            }
        }


        private static void ConsolePrint(Type valTp, object val, string nulStr)
        {
            if (!valTp.IsPrimitive)
            {
                if (valTp.FullName == "System.String"
                    || valTp.FullName == "System.Guid")
                {
                    Console.Write(" " + val);
                }
                else
                {
                    val.ConsolePrintProperty(nulStr + "  ");
                }

            }
            else
            {
                Console.Write(" " + val);
            }
        }
    }
}
